package bz.ziro.kanbe.bean;

import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import com.google.appengine.api.datastore.Key;

import bz.ziro.kanbe.dao.CommentDao;
import bz.ziro.kanbe.dao.PageDao;
import bz.ziro.kanbe.logic.FirstLogic;
import bz.ziro.kanbe.model.Comment;
import bz.ziro.kanbe.model.Page;

/**
 * ページデータ
 * @author Administrator
 */
public class PageData {

    //@SuppressWarnings("unused")
    private static final Logger logger = Logger.getLogger(FirstLogic.class.getName());
   
    /**
     * 対象ページデータ
     */
    private Page page;
   
    /**
     * 引数データ
     */
    private ParamData param;

    /**
     * サイト属性マップ
     */
    private Map<String,String> siteDataMap = new HashMap<String,String>();
    /**
     * ページ属性マップ
     */
    private Map<String,String> pageDataMap = new HashMap<String,String>();

    /**
     * コンストラクタ
     * @param aPage
     */
    public PageData(Page aPage,ParamData data) {
        page = aPage;
        
        //XMLデータの作成
        setXMLMap(page.getSiteData(),siteDataMap);
        //XMLデータの作成
        setXMLMap(page.getPageData(),pageDataMap);
        
        param = data;
    }

    /**
     * 名称を取得
     * @return
     */
    public String getName() {
        return page.getName();
    }
    /**
     * 詳細を取得
     * @return
     */
    public String getDetail() {
        return page.getDetail();
    }
    /**
     * ページのURLを取得
     * @return
     */
    public String getUrl() {
        return "/?id=" + page.getKey().getId();
    }

    /**
     * 作成時刻の取得
     * @return
     */
    public String getCreateDate() {
    	return getCreateFormatDate("yyyy/MM/dd HH:mm:ss");
    }
    /**
     * 作成時刻の取得
     * @param string
     * @return
     */
    public String getCreateFormatDate(String string) {
		return getDate(page.getCreateDate(),string);
	}
    /**
     * 編集時刻の取得
     * @return
     */
    public String getEditDate() {
    	return getEditFormatDate("yyyy/MM/dd HH:mm:ss");
    }
    /**
     * 編集時刻の取得
     * @param string
     * @return
     */
    public String getEditFormatDate(String string) {
		return getDate(page.getEditDate(),string);
	}
   
    /**
     * 時刻の取得
     * @param aDate
     * @param format
     * @return
     */
    private String getDate(Date aDate, String format) {
    	if ( aDate == null ) {
    		return "";
    	}
    	return SiteData.getLocaleTime(aDate, format);
    }

	/**
     * サイトのデータを取得
     * @param aKey
     * @return
     */
    public String getSiteData(String aKey) {
        return siteDataMap.get(aKey);
    }
    /**
     * ページのデータを取得
     * @param aKey
     * @return
     */
    public String getPageData(String aKey) {
        return pageDataMap.get(aKey);
    }

    /**
     * 自分と同一階層の最新ページリスト
     * @param aNum
     * @return
     */
    public List<PageData> getList(int aNum) {
    	Integer pageNum = param.getPageNum();
        return getPagingList(aNum,pageNum);
    }
    /**
     * 自分と同一階層の最新ページリスト
     * @param aNum
     * @return
     */
    public List<PagingData> getLinkList(int aNum) {
    	return getLinkList(aNum,0);
    }

    /**
     * 自分と同一階層の最新ページリスト
     * @param aNum
     * @return
     */
    public List<PagingData> getLinkList(int aNum,int aLimit) {
    	Pager pager = PageDao.createPagePager(page.getParentPageKey(),
    			              String.valueOf(param.getPageNum()),aNum);
    	return getLinkList(pager,"page",aLimit);
    }
    /**
     * Pagerからリンクリストの作成
     * @param pager
     * @param prefix
     * @return
     */
    private List<PagingData> getLinkList(Pager pager,String prefix,Integer aLimit) {

    	List<Integer> pageList = new ArrayList<Integer>();
    	int maxPageNum = pager.getMaxPageNum();
   
    	int startIdx = 1;
    	int endIdx   = maxPageNum;

    	//リミットがない場合
    	if ( aLimit != 0 ) {

    		startIdx = pager.getNowPageNum();
    		endIdx = pager.getNowPageNum();
 
    		while ( true ) {
    			//すでにすべて同じ状態だった場合
    			if ( startIdx == 1 && endIdx == maxPageNum ) break;
    			//制限に達していたら
    			if ( (endIdx - startIdx + 1 ) == aLimit ) break;
    			//最大値でない場合
    			if ( endIdx != maxPageNum ) {
    				endIdx++;
    			}
    			//制限に達していたら
    			if ( (endIdx - startIdx + 1 ) == aLimit ) break;
    			//最小値でない場合
    			if ( startIdx != 1 ) {
    				startIdx--;
    			}
    		}
    	}

   		//ページ数回繰り返す
   		for ( int cnt = startIdx; cnt <= endIdx; ++cnt ) {
   			pageList.add(cnt);
   		}

    	//返すリンクリストを生成
    	List<PagingData> linkList = new ArrayList<PagingData>();
    	//ページ番号数回繰り返す
    	for ( Integer pageNum : pageList ) {
    		
    		PagingData data = new PagingData();
    		//URLを作成
    		String url = "/?id=" + page.getKey().getId() + "&" + prefix + "=" + pageNum;
    		data.setNum(String.valueOf(pageNum));
    		data.setUrl(url);
    		//リストに追加
    		linkList.add(data);
    	}
    	return linkList;
    }
    
    
    /**
     * 自分の子供のページ
     * @param aNum
     * @return
     */
    public List<PageData> getChildrenList(int aNum) {
    	Integer pageNum = param.getChildrenNum();
        return getChildrenPagingList(aNum,pageNum);
    }

    /**
     * ページングのリストを取得
     * @param aNum
     * @param aPaging
     * @return
     */
    private List<PageData> getPagingList(int aNum,int aPaging) {
        List<Page> pageList = PageDao.findParentList(page.getParentPageKey(),aNum,aPaging);
        return getPageDataList(pageList);
    }

    /**
     * 子ページのページングリストを取得
     * @param aNum
     * @param aPaging
     * @return
     */
    private List<PageData> getChildrenPagingList(int aNum,int aPaging) {
        List<Page> pageList = PageDao.findParentList(page.getKey(),aNum,aPaging);
        return getPageDataList(pageList);
    }
    /**
     * 自分と同一階層の最新ページリスト
     * @param aNum
     * @return
     */
    public List<PagingData> getChildrenLinkList(int aNum) {
    	return getChildrenLinkList(aNum,0);
    }

    /**
     * 自分と同一階層の最新ページリスト
     * @param aNum
     * @return
     */
    public List<PagingData> getChildrenLinkList(int aNum,int aLimit) {
    	Pager pager = PageDao.createPagePager(page.getKey(),
    			            String.valueOf(param.getChildrenNum()),aNum);
    	return getLinkList(pager,"child",aLimit);
    }
    /**
     * ページデータのリストを設定して取得
     * @param pageList
     * @return
     */
    private List<PageData> getPageDataList(List<Page> pageList) {
        List<PageData> pageDataList = new ArrayList<PageData>();
        for ( Page page : pageList ) {
            pageDataList.add(new PageData(page,param));
        }
        return pageDataList;
    }

    /**
     * ナビゲーションリストを取得
     * @return
     */
    public List<PageData> getNavigationList() {

        List<PageData> pageList = new ArrayList<PageData>();

        Page wkPage = page;
        //ページをルートまで検索する
        while ( true ) {

            //ページデータを先頭に追加
            pageList.add(0,new PageData(wkPage,param));

            //親のページキーを取得
            Key parentKey = wkPage.getParentPageKey();
            if ( parentKey == null ) break;

            //親ページを検索
            wkPage = PageDao.find(wkPage.getSiteKey().getId(), parentKey.getId());
        }
        return pageList;
    }
    
    /**
     * コメントリストを検索
     * @return
     */
    public List<Comment> getCommentList(int num) {
    	//コメントを検索
    	List<Comment> commentList = CommentDao.findList(page.getKey(), num);
        //ページをルートまで検索する
        return commentList;
    }
   
    /**
     * コメント投稿を行うUrlを取得
     * @return
     */
    public String getCommentUrl() {
    	return "./comment?id=" + page.getKey().getId();
    }

    /**
     * コメント投稿を行うUrlを取得
     * @return
     */
    public String getMailUrl() {
    	return "./sendMail?id=" + page.getKey().getId();
    }
    /**
     * ページデータをIDから取得
     * @param aId
     * @return
     */
    public PageData get(String aId) {
    	ParamData data = new ParamData();
        //ページデータを検索
        //TODO テストサイト表示用に取得方法を考える
        Page page = PageDao.findPublishPage(Long.valueOf(aId));
        return new PageData(page,data);
    }
    /**
     * XML文字列から属性マップを作製
     * @param aXmlData
     * @param pageDataMap2
     * @return
     */
    private void setXMLMap(String aXmlData, Map<String, String> map) {

        if ( aXmlData == null || aXmlData.equals("") ) return;

        // ドキュメントビルダーファクトリを生成
        DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance();
        try {
            // ドキュメントビルダーを生成
            DocumentBuilder builder = dbfactory.newDocumentBuilder();
            // パースを実行してDocumentオブジェクトを取得
            Document doc = builder.parse(new ByteArrayInputStream(aXmlData.getBytes("UTF-8")));

            Element root = doc.getDocumentElement();
            NodeList paramList = root.getElementsByTagName("parameter");

            //属性数回繰り返す
            for ( int cnt = 0; cnt < paramList.getLength(); ++cnt ) {
                Element dataElm = (Element)paramList.item(cnt);

                String defineName = dataElm.getAttribute("name");
                String textData = dataElm.getTextContent();
                map.put(defineName, textData);
            }
        } catch (Exception ex) {
        	logger.warning(ex.getMessage());
        }
    }
}
